package com.erci.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.RandomUtil;
import com.erci.constant.JwtClaimsConstant;
import com.erci.entity.DTO.*;
import com.erci.entity.User;
import com.erci.entity.UserLocal;
import com.erci.entity.VO.UserPhoneVO;
import com.erci.entity.VO.UserRegisterVO;
import com.erci.entity.VO.UserUserVO;
import com.erci.entity.VO.UserVO;
import com.erci.mapper.UserMapper;
import com.erci.properties.JwtProperties;
import com.erci.result.PageResult;
import com.erci.result.Result;
import com.erci.service.UserService;
import com.erci.utils.JwtUtil;
import com.erci.utils.RegexUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public PageResult queryList(Integer page, Integer pageSize, String keyword) {
        PageHelper.startPage(page, pageSize);
        Page<UserVO> pageList = userMapper.queryList(keyword);
        List<UserVO> list = pageList.getResult();
        long total = pageList.getTotal();
        return new PageResult(list,total );
    }
    ///////////新增
    @Override
    public void add(User user) {
        user.setCreateTime(LocalDateTime.now())
        ;
        user.setUpdateTime(LocalDateTime.now());
        //将密码加密MD5
        String password = user.getPassword();
        String md5Password= DigestUtils.md5DigestAsHex(password.getBytes());
        user.setPassword(md5Password);
        userMapper.add(user);
    }


    //删除
    @Override
    public void delete(UserDeleteDTO userDeleteDTO) {
        userMapper.deleteById(userDeleteDTO.getId());
    }

    //修改

    @Override
    public void update(UserUpdateDTO userUpdateDTO) {
        User user = new User();
        BeanUtils.copyProperties(userUpdateDTO,user);
        user.setUpdateTime(LocalDateTime.now());
        user.setId(userUpdateDTO.getId());
        userMapper.updateById(user);
    }
    ///////////////////////////////////////////////////////////////////////////


    @Override
    @Transactional
    public UserUserVO loginByPassword(LoginDTO loginDTO) {
        String username = loginDTO.getUsername();
        String password = loginDTO.getPassword();
        password= DigestUtils.md5DigestAsHex(password.getBytes());
        User user = userMapper.loginByPassword(username,password);
        if (user == null) {
            user = userMapper.loginByPhone(username,password);
            if (user == null) {
                return null;
            }
        }
        //登录成功后，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.EMP_ID, user.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                claims);

        UserLocal userLocal = new UserLocal();
        BeanUtils.copyProperties(user,userLocal);

        Map<String, Object> usermap = BeanUtil.beanToMap(userLocal,new HashMap<>(),
                CopyOptions.create().setIgnoreNullValue( true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        //7.3 保存
        stringRedisTemplate.opsForHash().putAll("login:token:"+userLocal.getId(),usermap);
        //7.4 设置token有效期 每访问一次 就刷新有效期
        stringRedisTemplate.expire("login:token:"+userLocal.getId(), 36000L, TimeUnit.MINUTES);

        UserUserVO userUserVO = new UserUserVO();
        BeanUtils.copyProperties(user,userUserVO);
        userUserVO.setToken( token);
        return userUserVO;
    }

    @Override
    public Result<String> sendSmsCode(String phone) {
        //1 校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2 不符合 返回错误信息
            return Result.error("手机号格式错误");
        }
        //3 符合 生成验证码
        String code = RandomUtil.randomNumbers(6);
        //4 保存验证码到 redis  // set key value ex 120
        stringRedisTemplate.opsForValue().set("login:code:" +phone,code,2, TimeUnit.MINUTES);
        //5 发送验证码
        System.out.println(code);
        //返回
        return Result.success("发送成功");
    }

    @Override
    @Transactional
    public Result<UserPhoneVO> smsLogin(String phone, String code) {
        // 1 校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2 不符合 返回错误信息
            return Result.error("手机号格式错误");
        }
        // 2 校验验证码  从redis中获取
        String cacheCode = stringRedisTemplate.opsForValue().get("login:code:" + phone);

        if(cacheCode == null || !cacheCode.equals(code)){
            // 3 不一致 返回错误信息
            return Result.error("验证码错误");
        }
        //4 一致 根据手机号查询用户 select * from tb_user where phone = ?
        User user = userMapper.findByPhone(phone);

        //5 判断用户是否存在
        if(user == null){
            //6 不存在 创建新用户并保存
            user = createUserWithPhone(phone);
        }//TODO 存在的话直接登录成功
        //7 保存用户信息到 redis中
        //7.1 生成token
        //登录成功后，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.EMP_ID, user.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                claims);

        //7.2 将user转换为hash (Map)   问题：stringRedisTemplate只能存string string
        UserPhoneVO userPhoneVO = BeanUtil.copyProperties(user,UserPhoneVO.class);
        userPhoneVO.setToken(token);

        UserLocal userLocal = new UserLocal();
        BeanUtils.copyProperties(user,userLocal);

        Map<String, Object> usermap = BeanUtil.beanToMap(userLocal,new HashMap<>(),
                CopyOptions.create().setIgnoreNullValue( true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
        //7.3 保存
        stringRedisTemplate.opsForHash().putAll("login:token:"+userLocal.getId(),usermap);
        //7.4 设置token有效期 每访问一次 就刷新有效期
        stringRedisTemplate.expire("login:token:"+userLocal.getId(), 36000L, TimeUnit.MINUTES);
        return Result.success(userPhoneVO);
    }

    @Override
    public Result<UserRegisterVO> register(LoginDTO loginDTO) {
        //创建用户
        User user = new User();
        user.setUsername(loginDTO.getUsername());
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setRole("user");
        user.setPassword(DigestUtils.md5DigestAsHex(loginDTO.getPassword().getBytes()));
        user.setAvatar("https://anime01.oss-cn-beijing.aliyuncs.com/291a83a1-76cf-4030-a722-89f4a78cada21754478423432.jpg");
        //保存用户
        userMapper.add(user);
        return Result.success(BeanUtil.copyProperties(user, UserRegisterVO.class));
    }

    private User createUserWithPhone(String phone) {
        //创建用户
        User user = new User();
        user.setPhone(phone);
        user.setUsername("ikun_"+RandomUtil.randomString(10));
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        user.setRole("user");
        user.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));
        user.setAvatar("https://anime01.oss-cn-beijing.aliyuncs.com/291a83a1-76cf-4030-a722-89f4a78cada21754478423432.jpg");
        //保存用户
        userMapper.add(user);
        return user;
    }
    ///个人中心

    @Override
    public void userUpdate(UserUserUpdateDTO userUserVO) {
        //更新数据库
        User user = new User();
        BeanUtils.copyProperties(userUserVO,user);
        user.setUpdateTime(LocalDateTime.now());

        if(user.getPassword() != null){
            //密码加密
            user.setPassword( DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        }

        userMapper.userUpdate(user);

        //更新redis

    }

    @Override
    public Result<String> bindPhone(LoginPhoneDTO loginPhoneDTO) {
        Integer id = loginPhoneDTO.getUserId();
        String phone = loginPhoneDTO.getPhone();
        String code = loginPhoneDTO.getCode();
        // 1 校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2 不符合 返回错误信息
            return Result.error("手机号格式错误");
        }
        // 2 校验验证码  从redis中获取
        String cacheCode = stringRedisTemplate.opsForValue().get("login:code:" + phone);

        if(cacheCode == null || !cacheCode.equals(code)){
            // 3 不一致 返回错误信息
            return Result.error("验证码错误");
        }
        userMapper.unbindPhone(id,phone);
        return Result.success("绑定成功");
    }

    @Override
    public Result<String> unbindPhone(LoginPhoneDTO loginPhoneDTO) {
        Integer id = loginPhoneDTO.getUserId();
        String phone = loginPhoneDTO.getPhone();
        String code = loginPhoneDTO.getCode();
        // 1 校验手机号
        if (RegexUtils.isPhoneInvalid(phone)) {
            //2 不符合 返回错误信息
            return Result.error("手机号格式错误");
        }
        // 2 校验验证码  从redis中获取
        String cacheCode = stringRedisTemplate.opsForValue().get("login:code:" + phone);

        if(cacheCode == null || !cacheCode.equals(code)){
            // 3 不一致 返回错误信息
            return Result.error("验证码错误");
        }
        phone = null;
        userMapper.unbindPhone(id,phone);
        return Result.success("解绑成功");
    }
}
